//
// impressionistUI.h
//
// The user interface part for the program.
//


#include <FL/fl_ask.h>

#include <math.h>

#include "impressionistUI.h"
#include "impressionist.h"


/*
//------------------------------ Widget Examples -------------------------------------------------
Here is some example code for all of the widgets that you may need to add to the 
project.  You can copy and paste these into your code and then change them to 
make them look how you want.  Descriptions for all of the widgets here can be found 
in links on the fltk help session page.

//---------Window/Dialog and Menubar-----------------------------------
	
	//----To install a window--------------------------
	Fl_Window* myWindow = new Fl_Window(600, 300, "MyWindow");
		myWindow->user_data((void*)(this));	// record self to be used by static callback functions
		
		// install menu bar
		myMenubar = new Fl_Menu_Bar(0, 0, 600, 25);
		Fl_Menu_Item ImpressionistUI::myMenuItems[] = {
			{ "&File",		0, 0, 0, FL_SUBMENU },
				{ "&Load...",	FL_ALT + 'l', (Fl_Callback *)ImpressionistUI::cb_load },
				{ "&Save...",	FL_ALT + 's', (Fl_Callback *)ImpressionistUI::cb_save }.
				{ "&Quit",			FL_ALT + 'q', (Fl_Callback *)ImpressionistUI::cb_exit },
				{ 0 },
			{ "&Edit",		0, 0, 0, FL_SUBMENU },
				{ "&Copy",FL_ALT + 'c', (Fl_Callback *)ImpressionistUI::cb_copy, (void *)COPY },
				{ "&Cut",	FL_ALT + 'x', (Fl_Callback *)ImpressionistUI::cb_cut, (void *)CUT },
				{ "&Paste",	FL_ALT + 'v', (Fl_Callback *)ImpressionistUI::cb_paste, (void *)PASTE },
				{ 0 },
			{ "&Help",		0, 0, 0, FL_SUBMENU },
				{ "&About",	FL_ALT + 'a', (Fl_Callback *)ImpressionistUI::cb_about },
				{ 0 },
			{ 0 }
		};
		myMenubar->menu(myMenuItems);
    m_mainWindow->end();

	//----The window callback--------------------------
	// One of the callbacks
	void ImpressionistUI::cb_load(Fl_Menu_* o, void* v) 
	{	
		ImpressionistDoc *pDoc=whoami(o)->getDocument();

		char* newfile = fl_file_chooser("Open File?", "*.bmp", pDoc->getImageName() );
		if (newfile != NULL) {
			pDoc->loadImage(newfile);
		}
	}


//------------Slider---------------------------------------

	//----To install a slider--------------------------
	Fl_Value_Slider * mySlider = new Fl_Value_Slider(10, 80, 300, 20, "My Value");
	mySlider->user_data((void*)(this));	// record self to be used by static callback functions
	mySlider->type(FL_HOR_NICE_SLIDER);
    mySlider->labelfont(FL_COURIER);
    mySlider->labelsize(12);
	mySlider->minimum(1);
	mySlider->maximum(40);
	mySlider->step(1);
	mySlider->value(m_nMyValue);
	mySlider->align(FL_ALIGN_RIGHT);
	mySlider->callback(cb_MyValueSlides);

	//----The slider callback--------------------------
	void ImpressionistUI::cb_MyValueSlides(Fl_Widget* o, void* v)
	{
		((ImpressionistUI*)(o->user_data()))->m_nMyValue=int( ((Fl_Slider *)o)->value() ) ;
	}
	

//------------Choice---------------------------------------
	
	//----To install a choice--------------------------
	Fl_Choice * myChoice = new Fl_Choice(50,10,150,25,"&myChoiceLabel");
	myChoice->user_data((void*)(this));	 // record self to be used by static callback functions
	Fl_Menu_Item ImpressionistUI::myChoiceMenu[3+1] = {
	  {"one",FL_ALT+'p', (Fl_Callback *)ImpressionistUI::cb_myChoice, (void *)ONE},
	  {"two",FL_ALT+'l', (Fl_Callback *)ImpressionistUI::cb_myChoice, (void *)TWO},
	  {"three",FL_ALT+'c', (Fl_Callback *)ImpressionistUI::cb_myChoice, (void *)THREE},
	  {0}
	};
	myChoice->menu(myChoiceMenu);
	myChoice->callback(cb_myChoice);
	
	//-----The choice callback-------------------------
	void ImpressionistUI::cb_myChoice(Fl_Widget* o, void* v)
	{
		ImpressionistUI* pUI=((ImpressionistUI *)(o->user_data()));
		ImpressionistDoc* pDoc=pUI->getDocument();

		int type=(int)v;

		pDoc->setMyType(type);
	}


//------------Button---------------------------------------

	//---To install a button---------------------------
	Fl_Button* myButton = new Fl_Button(330,220,50,20,"&myButtonLabel");
	myButton->user_data((void*)(this));   // record self to be used by static callback functions
	myButton->callback(cb_myButton);

	//---The button callback---------------------------
	void ImpressionistUI::cb_myButton(Fl_Widget* o, void* v)
	{
		ImpressionistUI* pUI=((ImpressionistUI*)(o->user_data()));
		ImpressionistDoc* pDoc = pUI->getDocument();
		pDoc->startPainting();
	}


//---------Light Button------------------------------------
	
	//---To install a light button---------------------
	Fl_Light_Button* myLightButton = new Fl_Light_Button(240,10,150,25,"&myLightButtonLabel");
	myLightButton->user_data((void*)(this));   // record self to be used by static callback functions
	myLightButton->callback(cb_myLightButton);

	//---The light button callback---------------------
	void ImpressionistUI::cb_myLightButton(Fl_Widget* o, void* v)
	{
		ImpressionistUI *pUI=((ImpressionistUI*)(o->user_data()));

		if (pUI->myBool==TRUE) pUI->myBool=FALSE;
		else pUI->myBool=TRUE;
	}

//----------Int Input--------------------------------------

    //---To install an int input-----------------------
	Fl_Int_Input* myInput = new Fl_Int_Input(200, 50, 5, 5, "&My Input");
	myInput->user_data((void*)(this));   // record self to be used by static callback functions
	myInput->callback(cb_myInput);

	//---The int input callback------------------------
	void ImpressionistUI::cb_myInput(Fl_Widget* o, void* v)
	{
		((ImpressionistUI*)(o->user_data()))->m_nMyInputValue=int( ((Fl_Int_Input *)o)->value() );
	}

//------------------------------------------------------------------------------------------------
*/

//------------------------------------- Help Functions --------------------------------------------

//------------------------------------------------------------
// This returns the UI, given the menu item.  It provides a
// link from the menu items to the UI
//------------------------------------------------------------
ImpressionistUI* ImpressionistUI::whoami(Fl_Menu_* o)	
{
	return ( (ImpressionistUI*)(o->parent()->user_data()) );
}

ImpressionistUI* ImpressionistUI::whoami(Fl_Widget* o)	
{
	return ( (ImpressionistUI*)(o->parent()->parent()->user_data()) );
}

//--------------------------------- Callback Functions --------------------------------------------

//------------------------------------------------------------------
// Brings up a file chooser and then loads the chosen image
// This is called by the UI when the load image menu item is chosen
//------------------------------------------------------------------
void ImpressionistUI::cb_load_image(Fl_Menu_* o, void* v) 
{
	// Clean up things...
	OriginalView* p = whoami(o)->m_origView;
	p->resetAxis();
	p->resetPoints();
	p->resetPatch();

	Impressionist *pDoc=whoami(o)->getDocument();

	char* newfile = fl_file_chooser("Open File?", "*.bmp", "" );
	if (newfile != NULL) {
		pDoc->loadImage(newfile);
	}
}


//------------------------------------------------------------
// Causes the Impressionist program to exit
// Called by the UI when the quit menu item is chosen
//------------------------------------------------------------
void ImpressionistUI::cb_exit(Fl_Menu_* o, void* v) 
{
	whoami(o)->m_mainWindow->hide();
	//whoami(o)->m_brushDialog->hide();

}



//-----------------------------------------------------------
// Brings up an about dialog box
// Called by the UI when the about menu item is chosen
//-----------------------------------------------------------
void ImpressionistUI::cb_about(Fl_Menu_* o, void* v) 
{
	fl_message("Intelligent Scissor \nDeveloped by: Li Zhaohua & Liu Yang \n");

}

void ImpressionistUI::cb_setX(Fl_Widget* o,void*){
	whoami(o)->m_origView->m_state =kX;
} 

void ImpressionistUI::cb_setY(Fl_Widget* o,void*){
	whoami(o)->m_origView->m_state =kY;
} 

void ImpressionistUI::cb_setZ(Fl_Widget* o,void*){
	whoami(o)->m_origView->m_state =kZ;
} 

void ImpressionistUI::cb_changePL(Fl_Widget* o,void*){
	whoami(o)->m_origView->m_state =kCalAxis;
	whoami(o)->m_origView->calAxis();
}

void ImpressionistUI::cb_resetPL(Fl_Widget* o,void*){
	whoami(o)->m_origView->resetAxis();
	whoami(o)->m_origView->redraw();
	whoami(o)->m_origView->m_state = kNone;
}

void ImpressionistUI::cb_rpStart(Fl_Widget* o,void*){
	whoami(o)->m_origView->m_state = kPoint;
}

void ImpressionistUI::cb_rpMove(Fl_Widget* o,void*){
	whoami(o)->m_origView->calHomo();
}

void ImpressionistUI::cb_rpReset(Fl_Widget* o,void*){
	whoami(o)->m_origView->m_state = kNone;
	whoami(o)->m_origView->resetPoints();
}

void ImpressionistUI::cb_vStart(Fl_Widget* o,void*){
	whoami(o)->m_origView->m_state = kVertical;
	whoami(o)->m_origView->resetPatch();
}

void ImpressionistUI::cb_vMove(Fl_Widget* o,void*){
	whoami(o)->m_origView->m_state = kConnect;
}

void ImpressionistUI::cb_vCal(Fl_Widget* o,void*){
	whoami(o)->m_origView->exportPatch();
	whoami(o)->m_origView->m_state = kNone;
}

void ImpressionistUI::cb_vReset(Fl_Widget* o,void*){
	whoami(o)->m_origView->m_state = kNone;
	whoami(o)->m_origView->resetPatch();
}

void ImpressionistUI::cb_m_rp1input(Fl_Widget* o,void* userdata){
	whoami(o)->updateLabel(1,2); 
	int x,y;
	const char* str = whoami(o)->m_rp1input->value();
	char ch;
	sscanf(str, "%d%c%d", &x,&ch, &y);
	whoami(o)->m_pDoc->p_x[0] = x;
	whoami(o)->m_pDoc->p_y[0] = y;
}

void ImpressionistUI::cb_m_rp2input(Fl_Widget* o,void* userdata){
	whoami(o)->updateLabel(2,2); 
	int x,y;
	const char* str = whoami(o)->m_rp2input->value();
	char ch;
	sscanf(str, "%d%c%d", &x,&ch, &y);
	whoami(o)->m_pDoc->p_x[1] = x;
	whoami(o)->m_pDoc->p_y[1] = y;
}

void ImpressionistUI::cb_m_rp3input(Fl_Widget* o,void* userdata){
	whoami(o)->updateLabel(3,2); 
	int x,y;
	const char* str = whoami(o)->m_rp3input->value();
	char ch;
	sscanf(str, "%d%c%d", &x,&ch, &y);
	whoami(o)->m_pDoc->p_x[2] = x;
	whoami(o)->m_pDoc->p_y[2] = y;
}

void ImpressionistUI::cb_m_rp4input(Fl_Widget* o,void* userdata){
	whoami(o)->updateLabel(4,2); 
	int x,y;
	const char* str = whoami(o)->m_rp4input->value();
	char ch;
	sscanf(str, "%d%c%d", &x,&ch, &y);
	whoami(o)->m_pDoc->p_x[3] = x;
	whoami(o)->m_pDoc->p_y[3] = y;
}

void ImpressionistUI::cb_m_rp5input(Fl_Widget* o,void* userdata){
	whoami(o)->updateLabel(5,2); 
	int x,y,z;
	const char* str = whoami(o)->m_rp5input->value();
	char ch, ch2;
	sscanf(str, "%d%c%d%c%d", &x,&ch, &y, &ch2, &z);
	whoami(o)->m_pDoc->r_x = x;
	whoami(o)->m_pDoc->r_y = y;
	whoami(o)->m_pDoc->r_z = z;
}

void ImpressionistUI::updateLabel(int id, int color){
	switch(id){
	case 1:
		m_rp1->labelcolor(color);	m_rp1->redraw();
		break;
	case 2:
		m_rp2->labelcolor(color);	m_rp2->redraw();
		break;
	case 3:
		m_rp3->labelcolor(color);	m_rp3->redraw();
		break;
	case 4:
		m_rp4->labelcolor(color);	m_rp4->redraw();
		break;
	case 5:
		m_rp5->labelcolor(color);	m_rp5->redraw();
		break;
	default:
		break;
	}
}

//---------------------------------- per instance functions --------------------------------------

//------------------------------------------------
// Return the ImpressionistDoc used
//------------------------------------------------
Impressionist* ImpressionistUI::getDocument()
{
	return m_pDoc;
}

//------------------------------------------------
// Draw the main window
//------------------------------------------------
void ImpressionistUI::show() {
	m_mainWindow->show();
	m_origView->show();
	m_panel->show();
}

//------------------------------------------------
// Change the paint and original window sizes to 
// w by h
//------------------------------------------------
void ImpressionistUI::resize_windows(int w, int h) {
	//m_paintView->size(w,h);
	m_origView->size(w,h);
}

//------------------------------------------------ 
// Set the ImpressionistDoc used by the UI to 
// communicate with the brushes 
//------------------------------------------------
void ImpressionistUI::setDocument(Impressionist* doc)
{
	m_pDoc = doc;
	m_origView->m_pDoc=doc;
}

// Main menu definition
Fl_Menu_Item ImpressionistUI::menuitems[] = {
	{ "&File",		0, 0, 0, FL_SUBMENU },
		{ "&Load Image...",	FL_ALT + 'l', (Fl_Callback *)ImpressionistUI::cb_load_image },
		{ "&Quit",			FL_ALT + 'q', (Fl_Callback *)ImpressionistUI::cb_exit },
		{ 0 },

	{ "&Help",		0, 0, 0, FL_SUBMENU },
		{ "&About",	FL_ALT + 'a', (Fl_Callback *)ImpressionistUI::cb_about },
		{ 0 },

	{ 0 }
};



//----------------------------------------------------
// Constructor.  Creates all of the widgets.
// Add new widgets here
//----------------------------------------------------
ImpressionistUI::ImpressionistUI() {
	// Create the main window
	m_mainWindow = new Fl_Window(WINDOW_WIDTH, WINDOW_HEIGHT, "Impressionist");
		m_mainWindow->user_data((void*)(this));	// record self to be used by static callback functions
		// install menu bar
		m_menubar = new Fl_Menu_Bar(0, 0, WINDOW_WIDTH, 25);
		m_menubar->menu(menuitems);

		// Create a group that will hold two sub windows inside the main
		// window
		Fl_Group* group = new Fl_Group(200, 25, VIEW_WIDTH - 200 , VIEW_HEIGHT);
			// install original view window
			m_origView = new OriginalView(200, 25, VIEW_WIDTH - 200, VIEW_HEIGHT, "This is the orig view");
			m_origView->box(FL_DOWN_FRAME);
			
		group->end();
		Fl_Group::current()->resizable(group);

		// Panel to hold buttons on left
		m_panel = new Fl_Group(0,50,200,150, "Axis for Vanishing Points");
			m_setX = new Fl_Button (50,50,100,25, "Set X");		m_setX->callback(cb_setX);
			m_setY = new Fl_Button (50, 75,100,25, "Set Y");	m_setY->callback(cb_setY);
			m_setZ = new Fl_Button (50,100,100,25, "Set Z");	m_setZ->callback(cb_setZ);
			m_changePL = new Fl_Button (50,125,100,25, "Calculate");		m_changePL->callback(cb_changePL);
			m_resetPL  = new Fl_Button (50,150,100,25, "Reset");	m_resetPL->callback(cb_resetPL);
		m_panel->end();
		m_panel->show();

		Fl_Group* g_plane = new Fl_Group(0, 200, 200, 250, "Reference Plane");
			m_rpStart = new Fl_Button (50,200,100,25, "Start");		m_rpStart->callback(cb_rpStart);
			m_rpReset = new Fl_Button (50,225,100,25, "Reset");		m_rpReset->callback(cb_rpReset);
			m_rp1 = new Fl_Box (0,250,100,25, "Point 1 is");	
			m_rp1input = new Fl_Input (100,250,100,25);		m_rp1input->value("100,0");	m_rp1input->callback(cb_m_rp1input);	m_rp1input->when(FL_WHEN_ENTER_KEY|FL_WHEN_NOT_CHANGED);
			m_rp2 = new Fl_Box (0,275,100,25, "Point 2 is");
			m_rp2input = new Fl_Input (100,275,100,25);		m_rp2input->value("0,100");	m_rp2input->callback(cb_m_rp2input);	m_rp2input->when(FL_WHEN_ENTER_KEY|FL_WHEN_NOT_CHANGED);
			m_rp3 = new Fl_Box (0,300,100,25, "Point 3 is");
			m_rp3input = new Fl_Input (100,300,100,25);		m_rp3input->value("0,0");	m_rp3input->callback(cb_m_rp3input);	m_rp3input->when(FL_WHEN_ENTER_KEY|FL_WHEN_NOT_CHANGED);
			m_rp4 = new Fl_Box (0,325,100,25, "Point 4 is");
			m_rp4input = new Fl_Input (100,325,100,25);		m_rp4input->value("100,100");	m_rp4input->callback(cb_m_rp4input);	m_rp4input->when(FL_WHEN_ENTER_KEY|FL_WHEN_NOT_CHANGED);
			Fl_Box* b1 = new Fl_Box (0,350,200,25, "Note: p5 is out of plane");
			m_rp5 = new Fl_Box (0,375,100,25, "Point 5 is");
			m_rp5input = new Fl_Input (100,375,100,25);		m_rp5input->value("0,0,100");	m_rp5input->callback(cb_m_rp5input);	m_rp5input->when(FL_WHEN_ENTER_KEY|FL_WHEN_NOT_CHANGED);
			m_rpMove = new Fl_Button (50,400, 100,25, "Cal Homo.");		m_rpMove->callback(cb_rpMove);
		g_plane->end();
		g_plane->show();

		Fl_Group* g_vertical = new Fl_Group(0,450,200,150, "Vertices and Patches");
			Fl_Box* b2 = new Fl_Box (0,490,200,10, "Starting pt is the pt in ref plane\nEndding pt is the pt in space");
			b2->align (FL_ALIGN_TOP);
			m_vStart =  new Fl_Button (50,500,100,25, "Start");		m_vStart->callback(cb_vStart);
			m_vMove=  new Fl_Button (50,525,100,25, "Connect");		m_vMove->callback(cb_vMove);
			m_vReset =  new Fl_Button (50,550,100,25, "Reset");		m_vReset->callback(cb_vReset);
			m_vCal = new Fl_Button (50,575,100,25, "Export");		m_vCal->callback(cb_vCal);
		g_vertical->end();
		g_vertical->show();

    m_mainWindow->end();

	// init values
	m_nSize = 10;

}
